package com.opensns.sinaweibo;

import org.json.JSONObject;

import android.content.Context;
import android.os.AsyncTask;

import com.opensns.android.OauthAccessToken;
import com.opensns.android.OauthDialog;
import com.opensns.android.OpenSns;
import com.opensns.android.OpenSnsException;
import com.opensns.android.OpenSnsExceptionHandler;
import com.opensns.android.Parameters;
import com.opensns.android.Utility;
import com.opensns.android.OauthDialog.OauthCallbackHandler;

public class SinaWeibo extends OpenSns {

	public static final String URL_API_SERVER = "https://api.weibo.com/2/";
	public static final String URL_AUTHORIZE = "https://api.weibo.com/oauth2/authorize";
	public static final String URL_ACCESS_TOKEN = "https://api.weibo.com/oauth2/access_token";
	public static String APP_KEY = "";
	public static String APP_SECRET = "";
	public static String CALLBACK_URL = "";
	
	private static SinaWeibo mInstance;

	public static SinaWeibo getInstance() {
		if (mInstance == null) {
			mInstance = new SinaWeibo();
		}
		return mInstance;
	}
	
	/**
	 * 进行新浪微博开放平台异步授权。<br/>
	 * 具体的授权方法参考 <a href="http://open.weibo.com/wiki/Oauth2">http://open.weibo.com/wiki/Oauth2</a> 。
	 * @param context 调用方法的上下文。
	 * @param callback 授权回调接口。
	 */
	public void authorize(Context context, final AuthorizeCallback callback) {
		
		OauthCallbackHandler handler = new OauthCallbackHandler() {
			
			@Override
			public void onError(Exception e) {
				if (callback != null) {
					callback.onError(e);
				}
			}
			
			@Override
			public void handleResponse(String callbackUrl) {
				Parameters params = Utility.parseUrl(callbackUrl.replace("#", "?"));
				String error = params.getValue("error");
		        String errorCode = params.getValue("error_code");
		        if (error == null && errorCode == null) {
		        	OauthAccessToken token = new OauthAccessToken(OauthAccessToken.SINAWEIBO_TOKEN);
		        	token.accessToken = params.getValue("access_token");
		        	token.refreshToken = params.getValue("refresh_token");
		        	token.uid = params.getValue("uid");
		        	token.setExpiresIn(params.getValue("expires_in"));
		        	SinaWeibo.getInstance().setAccessToken(token);
		        	if (callback != null) {
		        		callback.onCompleted(params);
					}
		        } else if (error.equals("access_denied")) {
		        	if (callback != null) {
		        		callback.onCanceled();
					}        	
		        } else {
		        	if (callback != null) {
		        		callback.onException(new OpenSnsException(errorCode, error));
					}
		        }
			}
			
			@Override
			public String getCallbackUrl() {
				return CALLBACK_URL;
			}
		};
		
		OauthDialog dialog = new OauthDialog(context, getOauthUrl(), handler);
		dialog.show();
	}
	
	/**
	 * 调用新浪微博开放平台 API。<br/>
	 * 具体的 API 信息参考 <a href="http://open.weibo.com/wiki/API文档_V2">http://open.weibo.com/wiki/API文档_V2</a> 。
	 * @param context 调用方法的上下文。
	 * @param api API 的名称。
	 * @param params 请求的参数。
	 * @param method 调用的方式，GET、POST等。
	 * @return 新浪微博开放平台返回的响应数据。
	 * @throws OpenSnsException 平台 API 调用异常信息，由新浪微博开放平台返回。
	 * @throws Exception 程序异常。
	 */
	public String request(Context context, String api, Parameters params, String method) 
			throws OpenSnsException, Exception {
		api = URL_API_SERVER + api;
		if (method == "GET") {
			return Utility.requestGet(context, api, params, exceptionHandler);
		} else if (method == "POST") {
			return Utility.requestPost(context, api, params, exceptionHandler);
		}		
		return null;
	}
	
	/**
	 * 异步调用新浪微博开放平台 API。<br/>
	 * 具体的 API 信息参考 <a href="http://open.weibo.com/wiki/API文档_V2">http://open.weibo.com/wiki/API文档_V2</a> 。
	 * @param context 调用方法的上下文。
	 * @param api API 的名称
	 * @param params 请求的参数。
	 * @param method 调用的方式，GET、POST等。
	 * @param callback 异步请求的回调接口。
	 */
	public void requestAsync(
			final Context context,
			final String api, 
			final Parameters params, 
			final String method, 
			final RequestCallback callback) {

		AsyncTask<Integer, Integer, Integer> async = new AsyncTask<Integer, Integer, Integer>() {
			
			private String response;
			private OpenSnsException mException;
			private Exception mError;

			@Override
			protected Integer doInBackground(Integer... ps) {
				try {
					response = request(context, api, params, method);
					return 0;
				} catch (OpenSnsException e) {
					response = null;
					mException = e;
					return 1;
				} catch (Exception e) {
					response = null;
					mError = e;
					return 2;
				}
			}
			
			@Override
			protected void onPostExecute(Integer result) {
				super.onPostExecute(result);
				if (callback != null) {
					switch (result) {
					case 0:
						callback.onComplete(response);
						break;
					case 1:
						callback.onException(mException);
						break;
					case 2:
						callback.onError(mError);
						break;
					default:
						break;
					}
				}
			}
			
		};
		
		async.execute(0);
	}
	
	/**
	 * 从 SharePreferences 中获取新浪微博开放平台的 Access Token。
	 * @param context 调用方法的上下文。
	 * @return 新浪微博开放平台的 Access Token。
	 */
	public static OauthAccessToken restoreAccessToken(Context context) {
		return Utility.restoreAccessToken(context, OauthAccessToken.SINAWEIBO_TOKEN);
	}
	
	/**
	 * 获取新浪微博开放平台 Oauth2.0 的授权URL。
	 * @return 授权URL。
	 */
	private static String getOauthUrl() {
		Parameters params = new Parameters();
		params.add("client_id", APP_KEY);
		params.add("redirect_uri", CALLBACK_URL);
		params.add("response_type", "token");
		params.add("display", "mobile");
		return Utility.buildUrl(URL_AUTHORIZE, params);
	}
	
	private final OpenSnsExceptionHandler exceptionHandler = new OpenSnsExceptionHandler() {
		
		@Override
		public OpenSnsException parseException(String response, int statusCode) {
			OpenSnsException ex = new OpenSnsException();
			ex.status = String.valueOf(statusCode);
			try {
				JSONObject json = new JSONObject(response);
				ex.error = json.optString("error_code", "");
				ex.message = json.optString("error", "");
				ex.request = json.optString("request", "");
			} catch (Exception e) {
				
			}
			return ex;
		}
		
	};

}

